同一个类下,调用方法,采用AopContext方式,解决Spring注解失效 您所在的位置:网站首页 SpringBoot报错javatimeLocalDateTime cannot be cast to 同一个类下,调用方法,采用AopContext方式,解决Spring注解失效

同一个类下,调用方法,采用AopContext方式,解决Spring注解失效

2024-07-15 05:29| 来源: 网络整理| 查看: 265

使用:AopContext.currentProxy() 这个解决Spring注解失效

原因简单来说: 同一个类内这样调用的话,只有第一次调用了动态代理生成的ProxyClass,之后一直用的是不带任何切面信息的

知道了原因,处理方法也特别简单只需要显示利用Spring暴露的AopContext即可

解决:

((YourClass) AopContext.currentProxy()).noTransactionTask(keyword);

例子:

public void noTransactionTask(String keyword){ // 注意这里 调用了代理类的方法 ((YourClass) AopContext.currentProxy()).transactionTask(keyword); } @Transactional void transactionTask(String keyword) { try { Thread.sleep(5000); } catch (InterruptedException e) { //logger //error tracking } System.out.println(keyword); }

spring boot注解记得要加上 @EnableAspectJAutoProxy(exposeProxy = true)来暴露AOP的Proxy对象才行,否则会报异常

Cannot find current proxy: Set 'exposeProxy' property on Advised to 'true' to make it available.

注意:exposeProxy = true 是用来暴露AOP的Proxy对象的 产生代理对象就必须要产生一个切面,如果没有,创建代理对象的时候我们会发现对象中的exposeProxy属性还是false,不管你是否设置了exposeProxy = true。

ProxyCreatorSupport的createAopProxy方法: 在这里插入图片描述

像@Async这个只是简单的ioc,而没有aop ,创建代理对象的时候我们会发现对象中的exposeProxy属性总是false

而@Transactional 会将类定义成是一个切面。所以我们可以用 AopContext.currentProxy() 来解决同一个类下,调用方法事务的问题

例子: @Async 想要用 AopContext.currentProxy() 最简单的方法就是在被调用方法上添加一个事务的注解 @Transactional :

@Transactional @Async void transactionTask(String keyword) { try { Thread.sleep(5000); } catch (InterruptedException e) { //logger //error tracking } System.out.println(keyword); }

其实以上通过 AopContext.currentProxy() 这个方法去解决Spring注解失效的问题不是好的方案

更为简单的解决方案:

1.将被调用方法放到另一个类中

2.@Autowired注解让spring自动注入ApplicationContext,通过applicationContext.getBean(YourClass.class)获取类,然后调用你的方法

/** * 注解让spring自动注入ApplicationContext */ @Autowired private ApplicationContext applicationContext;

3.web项目可以通过WebApplicationContext 获取Spring容器上下文,通过wac.getBean(YourClass.class)获取类,然后调用你的方法

WebApplicationContext wac = ContextLoader.getCurrentWebApplicationContext(); 或者 (通过request或session加载spring容器) WebApplicationContextUtils.getWebApplicationContext(request.getSession().getServletContext()); 或者 ServletContext application = ServletActionContext.getServletContext(); ApplicationContext ctx = WebApplicationContextUtils.getWebApplicationContext(application);

4.写一个工具类获取Spring 的bean,然后通过 SpringContextUtil去获取类,然后调用你的方法

SpringContextUtil.getBean(YourClass.class) import org.springframework.beans.BeansException; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware; import org.springframework.stereotype.Component; /** * Created by qinjp on 2018/3/28. */ @Component public class SpringContextUtil implements ApplicationContextAware { private static ApplicationContext applicationContext; @Autowired @Override public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { SpringContextUtil.applicationContext = applicationContext; } public static T getBean(Class clazz){ return applicationContext.getBean(clazz); } public static T getBean(String name, Class requiredType) { return applicationContext.getBean(name, requiredType); } }

5.通过ApplicationListener获取spring 的上下文容器 ,获取类,然后调用你的方法

@Component // 注入spring容器 public class SpringManager implements ApplicationListener { private static ApplicationContext applicationContext = null; @Override public void onApplicationEvent(ContextRefreshedEvent event) { if(applicationContext == null){ applicationContext = event.getApplicationContext(); } } public static ApplicationContext getApplicationContext() { return applicationContext; } public static T getBean(Class clazz){ return applicationContext.getBean(clazz); } }

6.spring boot 通过入口main函数获取spring 的上下文容器 ,获取类,然后调用你的方法

public static void main(String[] args) { ApplicationContext context = SpringApplication.run(Application.class, args); SpringContextUtil.setApplicationContext(context); } import org.springframework.context.ApplicationContext; public class SpringContextUtil { private static ApplicationContext applicationContext; public static ApplicationContext getApplicationContext(){ return applicationContext; } public static void setApplicationContext(ApplicationContext applicationContext){ SpringContextUtil.applicationContext = applicationContext; } public static T getBean(String name){ return (T)applicationContext.getBean(name); } public static T getBean(Class clazz){ return applicationContext.getBean(clazz); } }


【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有